<?php
/************************************
*   新浪相册 7.0
*   @file:k.php
*   @intro:
*   @author:shaopu@
*   @date:Sun Sep 20 17:33:00 CST 2009
************************************/

class K
{
    //公用数据池
    static $data_pool;
    /**
     * 加载参数
     *
     * @param string $name
     * @return array
     */
    static public function config($name)
    {
        $_name = 'CONFIG_'.$name;
        
        if(K::_is_set($_name))
            return K::_get($_name);
        
        if(!is_file(K5_CONFIG_PATH.'/'.$name.'.php'))
            K::halt('config '.$name.' not exists');
        $configs = include_once(K5_CONFIG_PATH.'/'.$name.'.php');
        
        if(!empty($configs))
            K::_set($_name , $configs);
        
        return $configs;
    }
    
    /**
     * 加载数据模型
     *
     * @param string $name
     * @return object / false
     */
	static public function load_mod($name)
	{
	    //缓存池中的KEY
		$_name = 'MOD_'.$name;
		//检测缓存池
		if(K::_is_set($_name))
		   return K::_get($_name);
		    
		//初始化模块对象
		$classname = 'mod_'.$name;
		$db_config = K::config('db_config');
		$key = 'default';
		if(!isset($db_config[$key]))
		    K::halt('db config not exist:'.$name);
		$mod_config = $db_config[$key];
		$obj = new $classname($mod_config);
		//存入缓存池
		K::_set($_name , $obj);
		
		return $obj;
	}
	/**
     * 加载应用模型
     *
     * @param string $name
     * @return object / false
     */
	static public function load_app($name)
	{
	    //缓存池中的KEY
		$_name = 'APP_'.$name;
		//检测缓存池
		if(K::_is_set($_name))
		   return K::_get($_name);  
		//初始化模块对象
		$classname = 'app_'.$name;
		$obj = new $classname();
		//存入缓存池
		K::_set($_name , $obj);
		
		return $obj;
	}
	/**
	 * 加载逻辑类
	 *
	 * @param string $name
	 */
	static public function load_logic($name)
	{
	    $class_name = 'lgc_'.$name;
	    $obj = new $class_name();
	    return $obj;
	}
	
	
	/**
	 * 加载数据库操作类
	 *
	 * @param string $type
	 * @return object / false
	 */
	static public function db($type = 'mysql')
	{
	    //缓存池中的KEY
	    $_name = 'DB_'.$type;
	    if(K::_is_set($_name))
	        return K::_get($_name);

	    $classname = 'lib_db_'.$type;
	    $db = new $classname;
	    
	    K::_set($_name , $db);
	    
	    return $db;
	}
	/**
	 * 加载MC操作类
	 *
	 * @param string $type
	 * @return object
	 */
	static public function mc($type = '')
	{
	    //缓存池中的KEY
	    $_name = 'MC_'.$type;
	    if(K::_is_set($_name))
	        return K::_get($_name);
	        
	    $K_MC_CONFIG = K::config('mc_config');
	    if(!isset($K_MC_CONFIG[$type]))
	        return false;

	    $mc = new lib_memcache($K_MC_CONFIG[$type]);
	    K::_set($_name , $mc);
	    
	    return $mc;
	}
	/**
	 * CACHE控制类实例
	 *
	 * @return object
	 */
	static public function cache()
	{
	    //缓存池中的KEY
	    $_name = 'MC_CACHE';
	    if(K::_is_set($_name))
	        return K::_get($_name);
	    
	    $obj = new mc_cache();
	    
	    K::_set($_name , $obj);
	    return $obj;
	}
	
	/**
	 * 投放队列进行处理
	 * 
	 * ex:
	 * K::throw_queue(K_QUEUE_KEY_PHOTO , '120' , serialize($aData));
	 *
	 * @param string $key
	 * @param int $sign
	 * @param string $value
	 * @return true
	 */
	static public function throw_queue($key , $sign , $value)
	{
	    if (!$key || !$sign || !$value)
		{
			K_log::debug('queue' , $key.'_'.$sign.'_'.$value ,'error');
			return false;
		}
		$_name = 'QUEUE_MC';
	    if(K::_get($_name))
	       $mc = self::_get($_name);
	    else 
	    {
    	    $mc = new Memcached();
            $mc->addServer(K_QUEUE_HOST , K_QUEUE_PORT);
            K::_set($_name , $mc);
	    }
        $mc->setOption(Memcached::OPT_COMPRESSION, false);
        //需要发送的数据
        $sData = ($sign ? $sign.',' : '') . $value;
        if(K5_DEBUG)
            K_log::debug('queue' , $sData , 'debug');
        //重复执行两次
        $bRs = $mc->set($key , $sData);
        if(!$bRs)
            $bRs = $mc->set($key , $sData);
            
        if(!$bRs)
        {
            K_log::alert(K5_LOG_ALERT_OTHER , 'queue' , 'set_error');//报警
            K_log::debug('queue' , $key.'_'.$sData ,'error');
        }
        return true;
	}
	/**
	 * 把未成功的SQL投给队列进行追加操作
	 *
	 * @param array $aSqlList
	 * @return true
	 */
	static public function throw_sql_queue($aSqlList)
	{
	    //记录一下追加执行的SQL用于了解错误情况
	    K_log::debug('sql_queue' , 'sql_n:'.count($aSqlList));
	    
	    if(is_array($aSqlList) && count($aSqlList))
	    {
    	    foreach ($aSqlList as $sql)
    	        K::throw_queue(K_QUEUE_KEY_SQL , '' , $sql);
	    }
	    return true;
	}
	
	
	/**
	 * 生成微秒级时间
	 *
	 * @return int
	 */
	static public function microtime()
	{
	    return array_sum(explode(' ' , microtime()));
	}
	/**
	 * 普通HASH算法　主要用来HASH数据库和表
	 *
	 * @param mix $key
	 * @param int $hash_n
	 * @return int
	 */
	static public function hash_table($u , $n = 128)
	{
	    $h  = sprintf("%u", crc32($u));
        $h1 = intval($h / $n);
        $h2 = $h1 % $n;
        $h3 = base_convert($h2, 10, 16);
        $h4 = sprintf("%02s", $h3);
        return $h4;
	}
	/**
	 * 哈希分库
	 *
	 * @param int $uid
	 * @param int $hash_n
	 * @return int
	 */
	static public function hash_db($uid , $hash_n = 4)
	{
	    $h  = sprintf("%u", crc32($uid));
    	$index = intval(fmod($h, $hash_n));
    	return $index;
	}
	
	static public function http_get(&$result , $host , $url , $port = 80 , $referer = K5_DOMAIN , $timeout = K5_HTTP_TIMEOUT)
	{
	    $url = 'http://'.trim($host , '/').':'.$port.$url;
	    
	    $ch_curl = curl_init();
		curl_setopt ($ch_curl, CURLOPT_TIMEOUT, $timeout);    
		curl_setopt ($ch_curl, CURLOPT_HEADER , false);
		curl_setopt($ch_curl, CURLOPT_RETURNTRANSFER,true);
		
		curl_setopt($ch_curl, CURLOPT_REFERER, $referer);     //
		curl_setopt ($ch_curl, CURLOPT_URL,$url);             //地址
		curl_setopt($ch_curl, CURLOPT_HTTPGET, 1);            //

		$iStartTime = K::microtime();
		//重复执行2次
		$result  = curl_exec($ch_curl);
		if($result === false)
		{
		    $iStartTime = K::microtime();
		    $result  = curl_exec($ch_curl);
		}
		if($result === false)
		{
		    $log = 'url:'.$url.TAB.'e:'.curl_error($ch_curl).TAB.'p:'.$port.TAB.'r:'.$referer.TAB.'t:'.$timeout;
		    K_log::debug('http_get' , $log , 'error');
		    K_log::alert(K5_LOG_ALERT_API , $host , 'connect_err');
		}
		
		if(K5_DEBUG)
		{
		    $iLastTime = K::microtime() - $iStartTime;
		    $log = 'url:'.$url.TAB.'rs:'.$result.TAB.'t:'.$iLastTime;
		    K_log::debug('http_get' , $log);
		}
		
		return $result === false ? false : true;
	}
	
	static public function http_post(&$result , $host , $url , $aData , $port = 80 , $referer = K5_DOMAIN , $timeout = K5_HTTP_TIMEOUT)
	{
	    $url = 'http://'.trim($host , '/').':'.$port.$url;
	    
	    $ch_curl = curl_init();
		curl_setopt ($ch_curl, CURLOPT_TIMEOUT, $timeout);        
		curl_setopt ($ch_curl, CURLOPT_HEADER , false);
		curl_setopt($ch_curl, CURLOPT_RETURNTRANSFER,true);
		
	    curl_setopt($ch_curl, CURLOPT_REFERER, $referer);      //referer
		curl_setopt ($ch_curl, CURLOPT_URL,$url);              //调用地址
		curl_setopt($ch_curl, CURLOPT_POST, 1);                //
		curl_setopt ($ch_curl, CURLOPT_POSTFIELDS,$aData);     //数据

		$iStartTime = K::microtime();
		$result  = curl_exec($ch_curl);
		if($result === false)
		{
		    $iStartTime = K::microtime();
		    $result  = curl_exec($ch_curl);
		    
		    $log = 'url:'.$url.' e:'.curl_error($ch_curl).' p:'.$port.' r:'.$referer.' t:'.$timeout;
		    K_log::debug('http_get' , $log , 'error');
		    K_log::alert(K5_LOG_ALERT_API , $host , 'connect_err');
		}
		
		if(K5_DEBUG)
		{
		    $iLastTime = K::microtime()-$iStartTime;
		    $log = 'url:'.$url.TAB.'rs:'.$result.TAB.'t:'.$iLastTime.TAB.'data:'.serialize($aData);
		    K_log::debug('http_get' , $log);
		}
		
		return $result === false ? false : true;
	}
	
	/**
	 * 生成SESSION对象
	 *
	 * @return object
	 */
	static public function session()
	{
	    if(K::_is_set('SESSION'))
	       return K::_get('SESSION');
	       
	    if(!isset($_COOKIE[K_SESSION_COOKIE_NAME]))
	    {
	        $session_id = md5(uniqid(microtime()));
	        setcookie(K_SESSION_COOKIE_NAME, $session_id, 0 , "/" , K5_ROOT_DOMAIN , false , true);
	    }
	    else 
	        $session_id = $_COOKIE[K_SESSION_COOKIE_NAME];
	        
	    //$obj_mc = K::mc('session');  //目前用不到MC
	    $obj_session = new lib_session($session_id , $obj_mc);
	    K::_set('SESSION' , $obj_session);
	    return $obj_session;
	}
	/**
	 * 系统错误强行退出
	 *
	 * @param string $log  需要记录的日志
	 */
	static public function halt($log)
	{
	    K_log::debug('halt' , K5_LOG_SIGN_ERROR.$log.$_SERVER['REQUEST_URI']);
	    die($log);
	}
    /**
     * 保存当前CONTROLLOR实例供别处调用
     *
     * @param object $obj
     */
	static public function set_controllor($obj)
	{
	    K::_set('CTRL' , $obj);
	}
	/**
	 * 取出当前CONTROLLOR实例
	 *
	 * @return object
	 */
	static public function controllor()
	{
	    return K::_get('CTRL');
	}
	
	/**
	 * 检测数据池中是否包含某值
	 *
	 * @param string $name
	 * @return bool
	 */
    static private function _is_set($name)
    {
        return isset(self::$data_pool[$name]);
    }
    /**
     * 将数据写入数据池
     *
     * @param string $name
     * @param mix $value
     * @return bool
     */
    static private function _set($name , $value)
    {
        self::$data_pool[$name] = $value;
        return true;
    }
    /**
     * 从数据池中取出某值
     *
     * @param string $name
     * @return mix
     */
    static private function &_get($name)
    {
        return self::$data_pool[$name];
    }

    /**
     * 检查是否含有危险关键字
     *
     * @param string $str
     * @return bool     true 危险 , false 安全
     */
    static public function is_bad_word($str)
    {
    	if($str == '')return false;
        //关键字过滤接口由社区搜索产品维护 guanlin@
        $mc = new Memcached();
        $mc->addServer(K_KEYWORD_FILTER_HOST , K_KEYWORD_FILTER_PORT);
        $mc->setOption(Memcached::OPT_COMPRESSION, false);
        
        $str_gb = K_str::utf2gb($str);//得是GBK的。
        $bRs = $mc->set('filter' , trim($str_gb));
        K_log::debug('is_bad_word' , $str .'---'. (int)$bRs);
        
        if($bRs == true)    //返回结果为TRUE表示是安全的
            return false;
        else 
        {
            //此时相当于从MC返回false，表示含有危险关键字
            if($mc->getResultCode() == Memcached::RES_NOTSTORED)
                return true;
            //其他情况可能是网络错误等，按安全输入进行，从而保证产品运行。
            else 
                return false;
        }
    }
    /**
     * SASS　过滤
     *
     * @param uid $uid
     * @param int $type K_SASS_TYPE_COMMENT K_SASS_TYPE_UPLOAD
     * @return bool true禁止 false通过
     */
    static public function is_sass_danger($uid , $type)
    {
        
        $ip = K::get_ip();
        $url = '/sass/interface/sass_data_input_output.php?iip='.$ip.'&iuid='.$uid.'&itype=135';
        $rs = K::http_get($sResult , K_SASS_HOST , $url , K_SASS_PORT);
        //SASS失效？放行
        if(!$rs)
            return false;
        $sResult = (int)$sResult;
        
        if($sResult > 0 && $sResult < 31)
        {
            K_log::debug('sass_deny' , $uid.TAB.$ip.TAB.$rs.TAB);
            return true;
        }
        
        return false;
    }
    /**
     * 取客户端IP
     * 注，内网接口的IP有时是调用方传来的，通过后面set_ip方法写入，在MODEL中通过本方法取出
     * 这样写保证IP不用传来传去。
     *
     * @return string
     */
    static public function get_ip()
    {
        $_name = 'UIP';
        if(K::_is_set($_name))
            return K::_get($_name);
            
        if ($ip = getenv('HTTP_X_FORWARDED_FOR'))
    	{
    		if(strstr($ip, ','))
    		{
    			$tmp = explode(',', $ip);
    
    			$tmp[1] = trim($tmp[1]);
    			$tmp[0] = trim($tmp[0]);
    
    			if(preg_match("/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $tmp[1]))
    			{
    				$ip = $tmp[1];
    			}
    			else if(preg_match("/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $tmp[0]))
    			{
    				$ip = $tmp[0];
    			}
    		}
    	}
    	else if(getenv('REMOTE_ADDR'))
    	{
    		$ip = getenv('REMOTE_ADDR');
    	}
    
    	return $ip;
    }
    /**
     * 设置客户端IP
     * 只在内网接口中使用，当用户真实IP是调用方以参数方式传入，通过本方法保存，在MODEL中使用。
     *
     * @param string $ip
     */
    static public function set_ip($ip)
    {
        $_name = 'UIP';
        K::_set($_name , $ip);
        return ;
    }

}

class K_log
{
    /**
     * 写入调试LOG
     *
     * @param string $dir
     * @param string $suffix
     * @param string $content
     */
	static public function debug($dir, $content , $suffix = '' )
	{
	    if(!K5_ENABLE_FILE_LOG)
	       return true;
		$dir = K5_LOG_PATH.'/debug/'.$dir;
		if(!is_dir($dir))
		{
		    mkdir($dir , '777');
		    chmod($dir , '777');
		}
		$content .= TAB.TAB.date('H:i:s').TAB.TAB.$_SERVER['REQUEST_URI'];
		
		self::__write($dir , $suffix , $content);
	}
	/**
     * 写入调试LOG
     *
     * @param string $dir
     * @param string $suffix
     * @param string $content
     */
	static public function alert($type , $where , $error)
	{
		$dir = K5_LOG_PATH;
		$content = time().' '.$type.TAB.TAB.$where.' '.$error;
		$content .= TAB.date('H:i:s').TAB.TAB.$_SERVER['REQUEST_URI'];
		
		$suffix = 'alert';
		self::__write($dir , $suffix , $content);
	}
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $type
	 * @param unknown_type $where
	 * @param unknown_type $error
	 */
	static public function api($content , $suffix='')
	{
		$dir = K5_LOG_PATH.'/api/';
		
		$content = time().TAB.$content.TAB.date('H:i:s').TAB.$_SERVER['REQUEST_URI'];
		
		self::__write($dir , $suffix , $content);
	}
	
	
	/**
	 * 实际写入LOG
	 *
	 * @param string $dir
	 * @param string $suffix
	 * @param string $content
	 */
	static private function __write($dir , $suffix , $content)
	{
		$filename = date('Y-m-d').($suffix ? '_'.$suffix : '').'.log';
		$filepath = $dir.'/'.$filename;
		
		$fp = fopen($filepath , 'a');
		fwrite($fp , $content.NL);
		fclose($fp);
		
		return ;
	}
}

class K_str
{
    /**
     * 取字符串宽度 中文算两个字符长
     * unicode 算作 4字符长度
     *
     * @param string $str
     * @return int
     */
    function str_width($str)
    {
        $str = preg_replace("/&(#\d{3,5});/", "__", $str);
        $str = preg_replace("/&([a-z]{2,7});/", "_", $str);
        return mb_strwidth($str , 'UTF-8');
    }
    
    /**
     * 字符串截取 按字符长度进行截取
     * 例：标题长度限制为8字符宽，用本函数进行截取
     *
     * @param string $str       //被截断的字串
     * @param int $start        //截断启始点
     * @param int $offset       //截断长度
     * @param string $suffix    //...
     * @return string
     */
    function substr($str , $start , $offset , $suffix = '')
    {
        $rs = mb_strimwidth($str , $start , $offset , '' , 'UTF-8');
        
        if(!empty($suffix))
        {
            $rs .= $rs <> $str ? $suffix : '';
        }
        
        return $rs;
    }
    
    /**
    * 转换字符串编码 从GB转到UTF-8
    *
    * @param string $str
    * @return string
    */
    function gb2utf($str)
    {
        return iconv('gbk' , 'utf-8//IGNORE' , $str);
    }
    /**
    * 转换字符串编码 从UTF-8到GBK
    * 对非GBK所能包含的字符转为HTML实体
    *
    * @param string $str
    * @return string
    */
    function utf2gb($string)
    {
        //造一个函数
        $call_back = create_function('$arr' , '
        $c = (int)$arr[1];  
        if(($c >= 19968 && $c <= 40869)       //中文字符
            || ($c >= 65280 && $c <= 65374)    //中文符号
            || ($c >= 12288 && $c <= 12585)   //中文符号
            || ($c >= 1040 && $c <= 1103)   //中文符号
            || ($c >= 65072 && $c <= 65131)   //中文符号
            || ($c >= 9472 && $c <= 9621))   //中文符号
        {
            return mb_convert_encoding($arr[0] , "GBK" ,"HTML-ENTITIES");
        }
        return $arr[0];
        ');

        $string = mb_convert_encoding($string , 'HTML-ENTITIES' , 'UTF-8');
        $string = preg_replace_callback("|&#([0-9]{1,5});|" , $call_back , $string);
        $string = K_str::htmlEntitiesSymbol_2_gbk($string);
        return $string;
    }
    /**
	 * 过滤字符串中的HTML标记 < >
	 * @param string $str 需要过滤的字符
	 * @return string
	 */
    function un_html($str)
    {
        K_str::esc_ascii($str);
        
		$str = stripslashes($str);
        $s	= array(
            "&"     => "&amp;",
            "<"	    => "&lt;",
            ">"	    => "&gt;",
            "\n"	=> "<br>",
            "\t"	=> "&nbsp;&nbsp;&nbsp;&nbsp;",
            "\r"	=> "",
            " "	    => "&nbsp;",
            "\""	=> "&quot;",
            "'"	    => "&#039;",
        );
        $str = strtr($str, $s);
        return $str;
    }
    /**
     * 过滤空字符
     *
     * @param string $str
     * @return string
     */
    function esc_ascii($str)
    {
        $esc_ascii_table = array(
        chr(0),chr(1), chr(2),chr(3),chr(4),chr(5),chr(6),chr(7),chr(8),
        chr(11),chr(12),chr(14),chr(15),chr(16),chr(17),chr(18),chr(19),
        chr(20),chr(21),chr(22),chr(23),chr(24),chr(25),chr(26),chr(27),chr(28),
        chr(29),chr(30),chr(31)
        );

        $str = str_replace($esc_ascii_table, '', $str);
        return $str;
    }
    /**
     * 转化URL为链接
     *
     * @param string $string
     * @return string
     */
    function url2link($string)
    {
        $string = preg_replace("/(^|\s|[^\w])([\.\w\-]+\@[\.\w\-]+\.[\.\w\-]+)/i", "\\1<a href=\"mailto:\\2\">\\2</a>", $string);

        $string = preg_replace("/(^|\s)((http|https|news|ftp):\/\/\w+[^\s<>\[\]]+)/i", "<a href=\"\\2\" target=\"_blank\">\\2</a>", $string);
        return $string;
    }
    
    function htmlEntitiesSymbol_2_gbk($string)
    {
        $arr_replace = array("&Alpha;" => "Α",
        "&Gamma;" => "Γ",
        "&Epsilon;" => "Ε",
        "&Eta;" => "Η",
        "&Iota;" => "Ι",
        "&Lambda;" => "Λ",
        "&Nu;" => "Ν",
        "&Omicron;" => "Ο",
        "&Rho;" => "Ρ",
        "&Tau;" => "Τ",
        "&Phi;" => "Φ",
        "&Psi;" => "Ψ",
        "&alpha;" => "α",
        "&gamma;" => "γ",
        "&epsilon;" => "ε",
        "&eta;" => "η",
        "&iota;" => "ι",
        "&lambda;" => "λ",
        "&nu;" => "ν",
        "&omicron;" => "ο",
        "&rho;" => "ρ",
        "&sigma;" => "σ",
        "&upsilon;" => "υ",
        "&chi;" => "χ",
        "&omega;" => "ω",
        "&uarr;" => "↑",
        "&darr;" => "↓",
        "&radic;" => "√",
        "&infin;" => "∞",
        "&and;" => "∧",
        "&cap;" => "∩",
        "&int;" => "∫",
        "&asymp;" => "≈",
        "&equiv;" => "≡",
        "&ge;" => "≥",
        "&Beta;" => "Β",
        "&Delta;" => "Δ",
        "&Zeta;" => "Ζ",
        "&Theta;" => "Θ",
        "&Kappa;" => "Κ",
        "&Mu;" => "Μ",
        "&Xi;" => "Ξ",
        "&Pi;" => "Π",
        "&Sigma;" => "Σ",
        "&Upsilon;" => "Υ",
        "&Chi;" => "Χ",
        "&Omega;" => "Ω",
        "&beta;" => "β",
        "&delta;" => "δ",
        "&zeta;" => "ζ",
        "&theta;" => "θ",
        "&kappa;" => "κ",
        "&mu;" => "μ",
        "&xi;" => "ξ",
        "&pi;" => "π",
        "&tau;" => "τ",
        "&phi;" => "φ",
        "&psi;" => "ψ",
        "&isin;" => "∈",
        "&sum;" => "∑",
        "&prop;" => "∝",
        "&ang;" => "∠",
        "&or;" => "∨",
        "&cup;" => "∪",
        "&there4;" => "∴",
        "&ne;" => "≠",
        "&le;" => "≤",
        "&larr;" => "←",
        "&rarr;" => "→",
        "&curren;" => "¤",
        "&hellip;" => "…",
        "&plusmn;" => "±",
        "&deg;" => "°",
        "&mdash;" => "—",
        "&ldquo;" => "“",
        "&rdquo;" => "”",
        "&middot;" => "·",
        "&lsquo;" => "‘",
        "&rsquo;" => "’");
                
        foreach ($arr_replace as $k => $v)
        {
            if(strpos($string , $k) <> false)
            {
                $string = str_replace($k , iconv('utf8' , 'gbk' , $v) , $string);
            }
        }
        return $string;
    }
    /**
     * 检查非法关键字
     *
     * @param string $str
     * @return bool true危险 false安全
     */
    function isWordDangerous($str)
    {
        return false;
    }
    
    // xml编码
	function xml_encode($data, $encoding = 'utf-8', $root = "root")
	{
		$xml = "<?xml version=\"1.0\" encoding=\"" . $encoding . "\"?>\n";
		$xml .= "<{$root}>\n";
		$xml .= self::_data_to_xml($data);
		$xml .= "</{$root}>";
		return $xml;
	}
	
	function _data_to_xml($data)
	{
		if (is_object($data))
		{
			$data = get_object_vars($data);
		}
		$xml = '';
		foreach($data as $key => $val)
		{
			is_numeric($key) && $key = "item id=\"$key\"";
			$xml .= "<$key>";
			if (is_array($val) || is_object($val))
			{
				$xml .= "\n" . self::_data_to_xml($val);
			}
			else 
			{
				$xml .= in_array($key, array('category', 'title', 'memo', 'tag')) ? "<![CDATA[" . $val . "]]>" : $val;
			}
			list($key,) = explode(' ', $key);
			$xml .= "</$key>\n";
		}
		return $xml;
	}

}



?>